[国家集训队]人员雇佣

2020-02-24
国家集训队

题意

有n个人,每个人都可以选择雇佣或不雇佣,雇佣需要$\{A_i\}$

如果两个人都被雇佣则会产生$E_{i,j}$的贡献,若只有一人被雇佣则产生$-E_{i,j}$的贡献

问最大收益

题解

$,,$

最小割模型,一个人要不付给他钱要不放弃收益

当且仅当其中一人被雇佣,中间的边要割

调试记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define LL long long
const int maxn = 1005;
const int S = 0;
const int T = 1001;
const int INF = 0x3f3f3f3f;
using namespace std;
struct E{
int to, nxt; LL f;
}e[maxn * maxn << 3];
int head[maxn], tot = 1;
void addedge(int u, int v, LL f){
e[++tot].to = v, e[tot].nxt = head[u], e[tot].f = f;
head[u] = tot;
}
void ins(int u, int v, int f){
addedge(u, v, f); addedge(v, u, 0);
}
int dep[maxn], now[maxn];
bool bfs(){
memset(dep, 0, sizeof dep); dep[S] = 1;
queue <int> q; while (!q.empty()) q.pop(); q.push(S);
memcpy(now, head, sizeof now);
while (!q.empty()){
int cur = q.front(); q.pop();
for (int i = head[cur]; i; i = e[i].nxt){
if (e[i].f > 0 && dep[e[i].to] == 0){
dep[e[i].to] = dep[cur] + 1;
q.push(e[i].to);
}
}
}
return (dep[T] != 0);
}
LL dfs(int cur, LL Max){
if (cur == T) return Max;
LL flow = 0;
for (int i = now[cur]; i; i = e[i].nxt){
int v = e[i].to; now[cur] = i;
if (e[i].f > 0 && dep[v] == dep[cur] + 1){
LL tmp = dfs(v, min(Max - flow, e[i].f));
e[i].f -= tmp; e[i ^ 1].f += tmp;
flow += tmp;
if (flow == Max) return flow;
}
}
return flow;
}
LL maxflow = 0;
void Dinic(){
while (bfs()) maxflow += dfs(S, INF);
}
int n; LL ans = 0;
int main(){
scanf("%d", &n);
for (int a, i = 1; i <= n; i++){
scanf("%d", &a);
ins(S, i, a);
}
for (int i = 1; i <= n; i++){
LL s = 0;
for (int e, j = 1; j <= n; j++){
scanf("%d", &e); ans += e; s += e;
ins(i, j, e * 2);
}
ins(i, T, s);
}
Dinic();
printf("%lld\n", ans - maxflow);
return 0;
}